﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Caching;
using System.Text;
using System.Threading.Tasks;

namespace Thrift.Utility
{
    internal static class CacheHelper
    {
        private const string CacheLockerPrefix = "CLP_";
        public static void RemoveFromCache(string cacheName, string cacheKey)
        {
            ICache instance = CacheFactory.GetInstance(cacheName);
            string text = CacheLockerPrefix + cacheName + cacheKey;
            lock (text)
            {
                instance.Remove(cacheKey);
            }
        }
        public static void RemoveFromLocalCache(string cacheKey)
        {
            string text = CacheLockerPrefix + cacheKey;
            lock (text)
            {
                MemoryCache.Default.Remove(cacheKey, null);
            }
        }
        public static T GetWithCache<T>(string cacheName, string cacheKey, Func<T> getter, bool absoluteExpiration = true, int cacheExpirationMinutes = 30) where T : class
        {
            ICache instance = CacheFactory.GetInstance(cacheName);
            T t = instance.Get(cacheKey) as T;
            if (t != null)
            {
                return t;
            }
            else
            {
                string text = CacheLockerPrefix + cacheName + cacheKey;
                lock (text)
                {
                    t = (instance.Get(cacheKey) as T);
                    if (t != null)
                    {
                        return t;
                    }
                    else
                    {
                        t = getter();
                        if (absoluteExpiration)
                        {
                            instance.Set(cacheKey, t, System.DateTime.Now.AddMinutes((double)cacheExpirationMinutes), null);
                        }
                        else
                        {
                            instance.Set(cacheKey, t, System.TimeSpan.FromMinutes((double)cacheExpirationMinutes), null);
                        }
                        return t;
                    }
                }
            }
        }

        public static T GetWithLocalCache<T>(string cacheKey, Func<T> getter, bool absoluteExpiration = true, int cacheExpirationMinutes = 30) where T : class
        {
            T t = MemoryCache.Default.Get(cacheKey, null) as T;
            if (t != null)
            {
                return t;
            }
            else
            {
                string text = CacheLockerPrefix + cacheKey;
                lock (text)
                {
                    t = (MemoryCache.Default.Get(cacheKey, null) as T);
                    if (t != null)
                    {
                        return t;
                    }
                    else
                    {
                        t = getter();
                        CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
                        if (absoluteExpiration)
                        {
                            cacheItemPolicy.AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddMinutes((double)cacheExpirationMinutes));
                        }
                        else
                        {
                            cacheItemPolicy.SlidingExpiration = TimeSpan.FromMinutes((double)cacheExpirationMinutes);
                        }
                        MemoryCache.Default.Set(cacheKey, t, cacheItemPolicy, null);
                        return t;
                    }
                }
            }
        }

        public static T GetWithLocalCache<T>(string cacheKey, Func<T> getter, params string[] filePathList) where T : class
        {
            T t = MemoryCache.Default.Get(cacheKey, null) as T;
            if (t != null)
            {
                return t;
            }
            else
            {
                string text = CacheLockerPrefix + cacheKey;
                lock (text)
                {
                    t = (MemoryCache.Default.Get(cacheKey, null) as T);
                    if (t != null)
                    {
                        return t;
                    }
                    else
                    {
                        t = getter();
                        List<string> list = new List<string>(filePathList.Length);
                        foreach (var path in filePathList)
                        {
                            if (File.Exists(path))
                            {
                                list.Add(path);
                            }
                        }
                        if (list.Count > 0)
                        {
                            CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
                            cacheItemPolicy.ChangeMonitors.Add(new HostFileChangeMonitor(list));
                            MemoryCache.Default.Set(cacheKey, t, cacheItemPolicy, null);
                        }
                        return t;
                    }
                }
            }
        }
        
        public static string ReadTextFileWithLocalCache(string filePath)
        {
            if (!File.Exists(filePath))
            {
                return string.Empty;
            }
            else
            {
                FileInfo fileInfo = new FileInfo(filePath);
                string cacheKey = fileInfo.FullName.ToUpper().GetHashCode().ToString();
                string t = GetWithLocalCache<string>(cacheKey, () => LoadRawString(filePath), new string[]
				{
					filePath
				});
                return t;
            }
        }

        public static T ReadXmlFileWithLocalCache<T>(string filePath) where T : class
        {
            if (!File.Exists(filePath))
            {
                return default(T);
            }
            else
            {
                FileInfo fileInfo = new FileInfo(filePath);
                string cacheKey = "XmlFileCache_" + fileInfo.FullName.ToUpper().GetHashCode().ToString();
                T t = GetWithLocalCache<T>(cacheKey, () => SerializeHelper.LoadFromXml<T>(filePath), new string[]
				{
					filePath
				});
                return t;
            }            
        }

        public static T ReadJsonFileWithLocalCache<T>(string filePath) where T : class
        {
            if (!File.Exists(filePath))
            {
                return default(T);
            }
            else
            {
                FileInfo fileInfo = new FileInfo(filePath);
                string cacheKey = "JsonFileCache_" + fileInfo.FullName.ToUpper().GetHashCode().ToString();
                T t = GetWithLocalCache<T>(cacheKey, () => SerializeHelper.JsonDeserialize<T>(LoadRawString(filePath)), new string[]
				{
					filePath
				});
                return t;
            }            
        }

        private static string LoadRawString(string filePath)
        {
            string result;
            using (StreamReader streamReader = new StreamReader(filePath, Encoding.GetEncoding("gb2312"), true))
            {
                result = streamReader.ReadToEnd();
            }
            return result;
        }
        
    }
}
